﻿using System;
using System.IO;
using System.Runtime.CompilerServices;


public class WaveFormatEx
{
    public const short FormatIEEE = 3;
    public const short FormatPCM = 1;
    public const uint SizeOf = 0x12;

    public long AudioDurationFromBufferSize(uint cbAudioDataSize)
    {
        if (this.AvgBytesPerSec == 0)
        {
            return 0L;
        }
        return (long)(((long)(cbAudioDataSize * 10000000)) / ((long)this.AvgBytesPerSec));
    }

    public long BufferSizeFromAudioDuration(long duration)
    {
        long num = (duration * this.AvgBytesPerSec) / 10000000L;
        uint num2 = (uint) (num % ((long) this.BlockAlign));
        if (num2 != 0)
        {
            num += this.BlockAlign - num2;
        }
        return num;
    }

    public byte[] ToByteArray(Stream readyStream)
    {
        int length = 0;
        if (readyStream != null)
        {
            length = (int) readyStream.Length;
        }
        using (MemoryStream ms = new MemoryStream())
        {
            using (BinaryWriter bw = new BinaryWriter(ms))
            {
                bw.Write(new char[4] { 'R', 'I', 'F', 'F' });
                bw.Write(length-8);
                bw.Write(new char[8] { 'W', 'A', 'V', 'E', 'f', 'm', 't', ' ' });
                bw.Write((int)16);
                bw.Write((short)1);
                bw.Write(Channels);
                bw.Write(SamplesPerSec);
                bw.Write((int)(SamplesPerSec * ((BitsPerSample * Channels) / 8)));
                bw.Write((short)((BitsPerSample * Channels) / 8));
                bw.Write(BitsPerSample);
                bw.Write(new char[4] { 'd', 'a', 't', 'a' });
                bw.Write(length-44);
                return GetTrueMemoryBuffer(ms);
            }
        }
    }
    public static byte[] GetTrueMemoryBuffer(MemoryStream stream)
    {
        byte[] filledBuffer = new byte[stream.Length];
        Array.Copy(stream.GetBuffer(), filledBuffer, (int)stream.Length);
        return filledBuffer;
    }

    public void SetFromByteArray(byte[] byteArray)
    {
        if ((byteArray.Length + 2) < 0x12L)
        {
            throw new ArgumentException("Byte array is too small");
        }
        this.FormatTag = BitConverter.ToInt16(byteArray, 0);
        this.Channels = BitConverter.ToInt16(byteArray, 2);
        this.SamplesPerSec = BitConverter.ToInt32(byteArray, 4);
        this.AvgBytesPerSec = BitConverter.ToInt32(byteArray, 8);
        this.BlockAlign = BitConverter.ToInt16(byteArray, 12);
        this.BitsPerSample = BitConverter.ToInt16(byteArray, 14);
        if (byteArray.Length >= 0x12L)
        {
            this.Size = BitConverter.ToInt16(byteArray, 0x10);
        }
        else
        {
            this.Size = 0;
        }
        if (byteArray.Length > 0x12L)
        {
            this.ext = new byte[byteArray.Length - 0x12L];
            Array.Copy(byteArray, 0x12, this.ext, 0, this.ext.Length);
        }
        else
        {
            this.ext = null;
        }
    }

    public string ToHexString()
    {
        string str = "";
        return ((((str + ToLittleEndianString(string.Format("{0:X4}", this.FormatTag))) + ToLittleEndianString(string.Format("{0:X4}", this.Channels)) + ToLittleEndianString(string.Format("{0:X8}", this.SamplesPerSec))) + ToLittleEndianString(string.Format("{0:X8}", this.AvgBytesPerSec)) + ToLittleEndianString(string.Format("{0:X4}", this.BlockAlign))) + ToLittleEndianString(string.Format("{0:X4}", this.BitsPerSample)) + ToLittleEndianString(string.Format("{0:X4}", this.Size)));
    }

    public static string ToLittleEndianString(string bigEndianString)
    {
        if (bigEndianString == null)
        {
            return "";
        }
        char[] chArray = bigEndianString.ToCharArray();
        if ((chArray.Length % 2) != 0)
        {
            return "";
        }
        for (int i = 0; i < (chArray.Length / 2); i += 2)
        {
            int index = i;
            int num3 = i + 1;
            int num4 = (chArray.Length - 2) - i;
            int num5 = (chArray.Length - 1) - i;
            char ch = chArray[index];
            char ch2 = chArray[num3];
            char ch3 = chArray[num4];
            char ch4 = chArray[num5];
            chArray[num4] = ch;
            chArray[num5] = ch2;
            chArray[index] = ch3;
            chArray[num3] = ch4;
        }
        return new string(chArray);
    }

    public override string ToString()
    {
        char[] array = new char[0x12];
        BitConverter.GetBytes(this.FormatTag).CopyTo(array, 0);
        BitConverter.GetBytes(this.Channels).CopyTo(array, 2);
        BitConverter.GetBytes(this.SamplesPerSec).CopyTo(array, 4);
        BitConverter.GetBytes(this.AvgBytesPerSec).CopyTo(array, 8);
        BitConverter.GetBytes(this.BlockAlign).CopyTo(array, 12);
        BitConverter.GetBytes(this.BitsPerSample).CopyTo(array, 14);
        BitConverter.GetBytes(this.Size).CopyTo(array, 0x10);
        return new string(array);
    }

    public void ValidateWaveFormat()
    {
        if (this.FormatTag != 1)
        {
            throw new ArgumentException("Only PCM format is supported");
        }
        if ((this.Channels != 1) && (this.Channels != 2))
        {
            throw new ArgumentException("Only 1 or 2 channels are supported");
        }
        if ((this.BitsPerSample != 8) && (this.BitsPerSample != 0x10))
        {
            throw new ArgumentException("Only 8 or 16 bit samples are supported");
        }
        if (this.Size != 0)
        {
            throw new ArgumentException("Size must be 0");
        }
        if (this.BlockAlign != (this.Channels * (this.BitsPerSample / 8)))
        {
            throw new ArgumentException("Block Alignment is incorrect");
        }
        if (this.SamplesPerSec > (0xffffffffL / ((long) this.BlockAlign)))
        {
            throw new ArgumentException("SamplesPerSec overflows");
        }
        if (this.AvgBytesPerSec != (this.SamplesPerSec * this.BlockAlign))
        {
            throw new ArgumentException("AvgBytesPerSec is wrong");
        }
    }

    public int AvgBytesPerSec { get; set; }

    public short BitsPerSample { get; set; }

    public short BlockAlign { get; set; }

    public short Channels { get; set; }

    public byte[] ext { get; set; }

    public short FormatTag { get; set; }

    public int SamplesPerSec { get; set; }

    public short Size { get; set; }
}

